package org.geektimes.configuration.microprofile.config;

import org.eclipse.microprofile.config.Config;
import org.eclipse.microprofile.config.ConfigValue;
import org.eclipse.microprofile.config.spi.ConfigSource;
import org.eclipse.microprofile.config.spi.Converter;

import java.lang.reflect.ParameterizedType;
import java.util.*;

public class JavaConfig implements Config {

    //存放配置源
    private List<ConfigSource> configSources = new LinkedList();

    private static Comparator<ConfigSource> configSourceComparator = new Comparator<ConfigSource>() {
        @Override
        public int compare(ConfigSource o1, ConfigSource o2) {
            //越大越优先
            return Integer.compare(o2.getOrdinal(),o1.getOrdinal());
        }
    };

    //存放转换器
    private Map<String,Converter> converterMap = new HashMap();

    public JavaConfig(){
        //加载所有配置源
        ClassLoader classLoader = getClass().getClassLoader();
        final ServiceLoader<ConfigSource> configSourceServiceLoader = ServiceLoader.load(ConfigSource.class, classLoader);
        configSourceServiceLoader.forEach(configSources::add);
        //根据优先级排序
        configSources.sort(configSourceComparator);

        //加载所有转换器
        final ServiceLoader<Converter> converterServiceLoader = ServiceLoader.load(Converter.class, classLoader);
        converterServiceLoader.forEach(converter -> {
            //获取泛型类型
            ParameterizedType type = (ParameterizedType) converter.getClass().getGenericInterfaces()[0];
            converterMap.put(type.getActualTypeArguments()[0].getTypeName(),converter);
        });
    }

    @Override
    public <T> T getValue(String s, Class<T> aClass) {
        String propertyValue = getPropertyValue(s);
        if(propertyValue == null){
            return null;
        }
        Optional<Converter<T>> optional = getConverter(aClass);
        if(optional.isPresent()){
            return optional.get().convert(propertyValue);
        }
        return null;
    }

    protected String getPropertyValue(String propertyName){
        String propertyValue = null;
        for (ConfigSource configSource : configSources) {
            propertyValue = configSource.getValue(propertyName);
            if(null != propertyValue){
                break;
            }
        }
        return propertyValue;
    }

    @Override
    public ConfigValue getConfigValue(String s) {
        return null;
    }

    @Override
    public <T> Optional<T> getOptionalValue(String s, Class<T> aClass) {
        T value = getValue(s,aClass);
        return Optional.ofNullable(value);
    }

    @Override
    public Iterable<String> getPropertyNames() {
        return null;
    }

    @Override
    public Iterable<ConfigSource> getConfigSources() {
        return Collections.unmodifiableList(configSources);
    }

    @Override
    public <T> Optional<Converter<T>> getConverter(Class<T> aClass) {
        return Optional.ofNullable(converterMap.get(aClass.getName()));
    }

    @Override
    public <T> T unwrap(Class<T> aClass) {
        return null;
    }
}
